package me.szlx.validation.system;

import me.szlx.validation.Constraint;
import me.szlx.validation.ConstraintFactory;
import me.szlx.validation.bundle.ConstraintBundle;
import me.szlx.validation.container.ConstraintContainer;
import me.szlx.validation.container.ModularContainer;
import me.szlx.validation.container.PriorityContainer;
import me.szlx.validation.exception.ExceptionManager;
import me.szlx.validation.exception.InvalidException;

/**
 * 约束系统的默认实现，能满足大多数场景的使用要求。
 */
public class DefaultConstraintSystem implements ConstraintSystem {
    private final ConstraintContainer constraintContainer;
    private final ExceptionManager exceptionManager;

    public DefaultConstraintSystem() {
        this(new ModularContainer(new PriorityContainer()), new InvalidException.Manager());
    }

    public DefaultConstraintSystem(ConstraintContainer constraintContainer, ExceptionManager exceptionManager) {
        this.constraintContainer = constraintContainer != null ? constraintContainer : new ModularContainer(new PriorityContainer());
        this.exceptionManager = exceptionManager != null ? exceptionManager : new InvalidException.Manager();
    }

    @Override
    public void install(ConstraintBundle constraintBundle) {
        constraintContainer.install(constraintBundle);
    }

    @Override
    public void install(Constraint... constraints) {
        if (constraints != null && constraints.length > 0) {
            constraintContainer.install(constraints);
        }
    }

    @Override
    public <T extends Constraint> T find(String constraintCodeOrBrief) {
        return constraintContainer.find(constraintCodeOrBrief);
    }

    @Override
    public RuntimeException createException(Constraint constraint) {
        return exceptionManager.create(constraint, null);
    }

    @Override
    public RuntimeException createException(Constraint constraint, String brief) {
        if (brief != null && !brief.equals(constraint.brief())) {
            return createException(ConstraintFactory.create(constraint.code(), brief));
        }
        return createException(constraint);
    }

    @Override
    public RuntimeException createException(Constraint constraint, Throwable cause) {
        return exceptionManager.create(constraint, cause);
    }

    @Override
    public RuntimeException createException(Constraint constraint, String brief, Throwable cause) {
        if (brief != null && !brief.equals(constraint.brief())) {
            return createException(ConstraintFactory.create(constraint.code(), brief), cause);
        }
        return createException(constraint, cause);
    }
}